
/*******************************************************
 *
 *  Routing Table Routines for EECE 494, Assignment 2.
 *
 *  Created by _________, University of British Columbia
 *  Jordan Chin 12558078
 *  Ritwik Chowdhury 71513063
 *  John de Vera 17728072
 *  Dennis Tsang 69972065
 *
 *  This is where you will put your routines to implement
 *  the routing table.  You should use the headers as
 *  supplied.  All your code will go in this
 *  file (and in cam.h)
 *
 ******************************************************/

#include "defs.h"

/* Note that you probably want to have a data structure
   that is accessable to all routines in this file.  To do
   this, you probably would define some structure (perhaps
   called cam_t in the file cam.h.  Then you could 
   create a variable of this type here by using:

   cam_t cam;

   This will create  a variable called cam (of type cam_h)
   that can be accessed by any routine in this file.  */

cam_list_t *cam_hash[HASH_SIZE];

int get_hash(ip_address_t *address)
{
    int key = address->n1 +
                PRIME_OFFSET_1 * address->n2 +
                PRIME_OFFSET_2 * address->n3 +
                PRIME_OFFSET_3 * address->n4;

    return key % HASH_SIZE;
}

void cam_delete_list(cam_list_t *list)
{
    if(list)
    {
        cam_list_t *cur = list;
        cam_list_t *next;

        free(cur->addr);

        next = cur->next;
        free(cur);
        cur = next;

        while(next)
        {
            free(next->addr);
            next = cur->next;
            free(cur);
            cur = next;
        }
    }
}

void cam_init()
{
    /* Write your code here */
    int i;
    for(i = 0; i < HASH_SIZE; i++)
    {
        cam_hash[i] = NULL;
    }
}


void cam_add_entry(ip_address_t *address, int port)
{
    /* Write your code here */
    int hash = get_hash(address);
    if(cam_hash[hash] == NULL)
    {
        cam_list_t *item = malloc(sizeof(cam_list_t));
        ip_address_t *addr = malloc(sizeof(ip_address_t));
        ip_address_copy(address, addr);
        item->addr = addr;
        item->port = port;
        item->next = NULL;
        cam_hash[hash] = item;
    }
    else
    {
        cam_list_t *cur = cam_hash[hash];
        while(cur->next != NULL)
        {
            cur = cur->next;
        }

        cam_list_t *item = malloc(sizeof(cam_list_t));
        ip_address_t *addr = malloc(sizeof(ip_address_t));
        ip_address_copy(address, addr);
        item->addr = addr;
        item->port = port;
        item->next = NULL;
        cur->next = item;
    }
}

inline BOOL equal_ip_addresses(ip_address_t *addr1, ip_address_t *addr2)
{
    return addr1->n1 == addr2->n1 && addr1->n2 == addr2->n2 &&
        addr1->n3 == addr2->n3 && addr1->n4 == addr2->n4;
}

int cam_lookup_address(ip_address_t *address)
{
    int hash = get_hash(address);
    cam_list_t *cur = cam_hash[hash];
    while(!equal_ip_addresses(address, cur->addr))
    {
        cur = cur->next;
    }

    return cur->port;
}

void cam_free()
{
    /* Write your code here */
    int i;
    for(i = 0; i < HASH_SIZE; i++)
    {
        cam_delete_list(cam_hash[i]);
    }
}
